package com.wyl.aop;

import com.wyl.aop.aspect.service.AspectAopService;
import com.wyl.aop.cglib.aop.CglibAopServiceProxyFactory;
import com.wyl.aop.cglib.service.impl.CglibAopServiceImpl;
import com.wyl.aop.jdk.aop.StarProxy;
import com.wyl.aop.jdk.service.Star;
import com.wyl.aop.jdk.service.impl.LiuDeHua;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 实现AOP的方式主要有以下几种：
 *
 * 基于动态代理：使用Java的Proxy类或CGLIB库创建代理对象，拦截目标方法并执行通知。
 * 基于编译时织入：使用AspectJ等工具将切面织入到Java字节码中，在编译期间生成增强后的代码。
 * 基于类加载器织入：使用AspectJ等工具在类加载时将切面织入到Java字节码中，生成增强后的类文件。
 * 基于注解：使用Spring AOP等框架，在目标方法上添加注解，并通过配置或自动扫描实现通知和切面。
 * 这些方式都可以实现AOP的功能，但它们各有优缺点。基于动态代理适用于对接口进行代理，而CGLIB则适用于代理具体类；基于编译时织入和类加载器织入可以获得更好的性能，但需要引入额外的工具和学习成本；基于注解可以方便地在代码中添加切点和通知，但可能会导致过多的注解和混乱的代码结构。选择哪种方式取决于您的需求和偏好，以及项目的具体情况。
 *
 * @author 吴宇亮 on 2023/5/8 17:47
 */
@RestController
public class AopTestController {

    @Autowired
    private AspectAopService aspectAopService;

    @RequestMapping("/cglibTest")
    public String cglibTest() {
        // cglib的实现原理：通过继承父类所有public方法，然后重写这些方法，在重写时增强这些方法
        // cglib aop不需要依赖接口，并且能触发this.public方法()的aop
        CglibAopServiceImpl cglibAopService = CglibAopServiceProxyFactory.createProxy();
        cglibAopService.getStr1("方法外引用调用方法");

        System.out.println("\n\n============================\n\n");

        // aspect的实现原理：通过持有目标对象来实现的，依赖接口
        // aspect aop依赖接口调用，并且不会触发this.方法()的aop
        aspectAopService.getStr1("方法外引用调用接口方法");

        System.out.println("\n\n============================\n\n");

        // jdk动态代理
        // 静态代理和动态代理的区别就是要代理的对象是不是可变的，比如StarProxy要代理的对象是可以传入可变的，所以是动态代理
        // jdk动态代理是通过持有对象来实现的
        StarProxy proxy = new StarProxy(new LiuDeHua());
        Star star = (Star)proxy.CreatProxyedObj();
        star.dance(10);

        return "hello";
    }
}
